﻿using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Web;
using System.Web.Routing;
using System.Web.SessionState;
using ManagedUIFlow.Infrastructure.Services;
using ManagedUIFlow.Infrastructure.Services.Helpers;
using ManagedUIFlow.Model;

namespace ManagedUIFlow.Application
{
    [SuppressMessage("Microsoft.Security", "CA2112:SecuredTypesShouldNotExposeFields", Justification = "There's nothing secret about the value of this field.")]
    public class AppHandler : IHttpHandler, IRequiresSessionState
    {
        private static readonly string MuifVersion = GetMvcVersionString();
        public static readonly string MuifVersionHeaderName = "X-AspNetMvcExtensions-Version";
        private ApplicationController _appController;
        private FlowViewServiceBuilder _flowViewServiceBuilder;

        public AppHandler(RequestContext requestContext)
        {
            if (requestContext == null)
            {
                throw new ArgumentNullException("requestContext");
            }

            RequestContext = requestContext;
        }                

        protected virtual bool IsReusable
        {
            get
            {
                return false;
            }
        }

        public FlowViewServiceBuilder FlowViewServiceBuilder
        {
            get
            {
                return _flowViewServiceBuilder ?? FlowViewServiceBuilder.Current;
            }
            set { _flowViewServiceBuilder = value; }
        }

        private FlowService _flowService;

        public FlowService FlowService
        {
            get
            {
                return _flowService ?? FlowService.Current;
            }
            set { _flowService = value; }
        }

        public ApplicationController ApplicationController
        {
            get
            {
                return _appController ?? ApplicationController.Current;
            }
            set
            {
                _appController = value;
            }
        }   

        public RequestContext RequestContext
        {
            get;
            private set;
        }
      
        public static bool DisableMvcResponseHeader
        {
            get;
            set;
        }      

        protected internal virtual void AddVersionHeader(HttpContextBase httpContext)
        {
            if (!DisableMvcResponseHeader)
            {
                httpContext.Response.AppendHeader(MuifVersionHeaderName, MuifVersion);
            }
        }

        private static string GetMvcVersionString()
        {
            // DevDiv 216459:
            // This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in
            // medium trust. However, Assembly.FullName *is* accessible in medium trust.
            return new AssemblyName(typeof(AppHandler).Assembly.FullName).Version.ToString(2);
        }

        protected virtual void ProcessRequest(HttpContext httpContext)
        {
            HttpContextBase iHttpContext = new HttpContextWrapper(httpContext);
            ProcessRequest(iHttpContext);
        }

        protected internal virtual void ProcessRequest(HttpContextBase httpContext)
        {
            //AddVersionHeader(httpContext);    
            ManagedFlow flow;
            if(!string.IsNullOrEmpty(RequestContext.GetState()))
            {
                var flowViewSerializer = FlowViewServiceBuilder.GetFlowViewService();
                flow = flowViewSerializer.Deserialize(RequestContext.GetKey(), RequestContext);      
            }
            else
            {
                var flowDefinition = FlowService.GetFlowDefinition(RequestContext.GetKey());
                if (flowDefinition == null)
                    throw new FlowException("No such flow found");

                flow = new ManagedFlow(Guid.NewGuid(), flowDefinition.Name, flowDefinition.StartupNavigation,
                                       flowDefinition.Redirectable,
                                       flowDefinition.RedirectUrl);
            }            
            ApplicationController.Execute(RequestContext, flow);
        }

        bool IHttpHandler.IsReusable
        {
            get
            {
                return IsReusable;
            }
        }

        void IHttpHandler.ProcessRequest(HttpContext httpContext)
        {
            ProcessRequest(httpContext);
        }
    }
}